%%@doc The dev_cards module is responsible the development cards. 
%%It calculates which development card is best to play at the moment and updates which development cards that 
%%is hold by the player and the probabilities of getting a specific card when buying development cards.
%%@end

-module(dev_cards).
-export([init/0,devCards/5,checkDevCards/3,moveRobberVal/5]).

%Jsettlers2 KNIGHT=0,ROADS=1,DISC (year of plenty)=2 MONO(monopoly)=3 rest vp: CAP=4 LIB=5 UNIV=6 TEM=7 TOW=8, UNKNOWN=9(om opponents drar kort)

%The initiation function for Dev. Cards
%Sets the starting probabilitys

%%@doc The init function sets the probabilities for a specific development card and spawns devCards.
%%@spec init() -> Pid
%%@end
init() -> 
    Probs = [{knight,14,14/25},
            {mono,2,2/25},
            {road,2,2/25},
            {vp,5,5/25},
            {year,2,2/25}],
    spawn(fun() -> devCards(0,[{knight,0},{road,0},{year,0},{mono,0},{vp,0}],Probs,25,[]) end).

%Main function for Dev. Cards Agent
%Handles all request from the actuator

%%@doc devCards receives messages from the actuator. It either update the development cards or call checkDevCards to send development card proposals to the actuator.
%%@spec devCards(NrMyCards,MyCards,Probabilities,TotalDevCardsNotPlayed,AgentIds) -> ok
%%@end
devCards(NrMyCards,MyCards,Probs,Total,IDs) -> 
    receive 
        {initIDs,NewIDs} -> devCards(NrMyCards,MyCards,Probs,Total,NewIDs);
        {update, CardsPlayed, Nr} ->
            newTotal = Total - Nr,
            devCards(NrMyCards,MyCards, updateProbs(Probs, CardsPlayed, newTotal),newTotal,IDs);
        {addCard,Type} -> {Type1,Nr} =  lists:keyfind(Type,1,MyCards),
                          NL = lists:keyreplace(Type1,1,MyCards,{Type1,Nr+1}),
                          %Prob borde uppdateras men det är jobbigt
                          devCards(NrMyCards+1,NL,Probs,Total,IDs);
        {action, Pid} -> Pid ! {responseDev,checkDevCards(IDs,MyCards,[]),NrMyCards},
						 devCards(NrMyCards,MyCards,Probs,Total,IDs);
		{removeCard, Type} -> {Type,Nr} =  lists:keyfind(Type,1,MyCards),
                          NL = lists:keyreplace(Type,1,MyCards,{Type,Nr-1}),
                          devCards(NrMyCards-1,NL,Probs,Total,IDs)

    end.

%%@doc checkDevCards checks the value of playing the different development cards hold by the player.
%%The value for a specific card is dependent on the environment. 
%%For instance the current game phase or the amount of victory points a specific card will generate.
%%@spec checkDevCards(AgentIds,Cards,EmptyListOfProposals) -> [Proposals :: {CardWeCanPlay,Value}]
%%@end
checkDevCards(IDs,[],Prop) -> Prop;
checkDevCards(IDs,[Card|Cards],Prop) ->
	io:fwrite("\tDev_Cards: ~w~n", [Card]),
	{opponents,OPid} = lists:keyfind(opponents,1,IDs),
	OPid ! {getPlayersVP,self()},
	receive
		{playersVP,[VP0,VP1,VP2,VP3]} -> false
	end,
	OPid ! {getPlayersKnights,self()},
	receive
		{playersKnights,[K0,K1,K2,K3]} -> false
	end,
	KM = lists:max([K1,K2,K3]),
	OPid ! {getPlayerLargestArmy,0,self()},
	receive
		{playerLA,LA0} -> false
	end,
	VPM = lists:max([VP1,VP2,VP3]),
	OPid ! {getPlayerWithLR,self()},
	receive
		{playerWithLR,Pn} -> false
	end,
	OPid ! {getPlayersRoads,self()},
	receive
		{playerRoads,[R0,R1,R2,R3]} -> false
	end,
	RM = lists:max([R1,R2,R3]),
	case Card of
		{knight,V} -> 
			if
				V == 0 ->
					checkDevCards(IDs,Cards,[{knight,0}|Prop]);
%				V > 1 ->
%					checkDevCards(IDs,Cards,[{knight,2}|Prop]);
				true -> io:fwrite("\tDev_Cards: Calculate Knight Value~n"),
					{robber,RPid} = lists:keyfind(robber,1,IDs),
					RPid ! {robberPos,self()},
					io:fwrite("\tDev_Cards: Wait for response from Robber~n"),
					receive 
						{robberPos,RP} -> io:fwrite("\tDev_Cards: Received Robber Pos~n"),
							{nodes,Nodes} = lists:keyfind(nodes,1,IDs),
							AdjNodes = lists:map(fun(X)-> case bot:getValue(RP+X,Nodes) of
								false -> 0;
								Nid   -> Nid!{robberInfo,self()}, 1
								end end, [1,18,33,16,-1,-16]),
								io:fwrite("\tDev_Cards: Wait for response from Adjacent Nodes~n"),
							receive 
								{nodeInfo,{Owner,Type}} -> 
									if 
										Owner == 0 ->
											io:fwrite("\tDev_Cards: We own blocked tile~n"),
											Val1 = moveRobberVal(1,IDs,Type,[VP0,VP1,VP2,VP3],VPM);
										true -> io:fwrite("\tDev_Cards: We don't own blocked tile~n"),
											Val1 = 0.0
									end,
									if
										(((K0 == 2) and (KM < 3)) or ((not LA0) and ((KM - K0) < 3))) ->
											io:fwrite("\tDev_Cards: We can take largest army~n"),
											Val2 = moveRobberVal(2,IDs,Type,[VP0,VP1,VP2,VP3],VPM),
											io:fwrite("\tDev_Cards: Value ~w~n",[Val2]);
										true -> 
											Val2 = 0.0
									end,
									if
										LA0 and (K0 == KM ) ->
											io:fwrite("\tDev_Cards: We defend largest army~n"),
											Val3 = moveRobberVal(3,IDs,Type,[VP0,VP1,VP2,VP3],VPM);
										true ->
											Val3 = 0.0
									end
							end,
							io:fwrite("\tDev_Cards: Value of Knight ~w~n",[Val1+Val2+Val3]),
							checkDevCards(IDs,Cards,[{knight,Val1+Val2+Val3}|Prop])
					end
			end;
		{mono,V} -> checkDevCards(IDs,Cards,[{monopoly,0,{0,0},[{clay,0},{ore,0},{sheep,0},{wheat,0},{wood,0}]}|Prop]);
		{year,V} ->
			if
				V == 0 ->
					checkDevCards(IDs,Cards,[{year,0,{0,0},[{clay,0},{ore,0},{sheep,0},{wheat,0},{wood,0}]}|Prop]);
				true ->
					{resources,RPid} = lists:keyfind(resources,1,IDs),
                    RPid ! {playYearOfPlenty,self()},
					receive
						{possibleBuilds,Pieces,Hand,Res,Val} -> false
					end,
					YRes = checkRes(Res,[0,0,0,0,0]),
					checkDevCards(IDs,Cards,[{year,YRes,{Pieces,Val},Hand}|Prop])
			end;
			{road,V} -> 
				if
					V == 0 -> 
						checkDevCards(IDs,Cards,[{road,1}|Prop]);
					true ->
						{opponents,OPid} = lists:keyfind(opponents,1,IDs),
						if
							Pn == -1 ->
								if 
									R0 > 2 ->
										if 
											VPM < 5 ->
												Val = 0.0;
											VP0 > 7 ->
												Val = 5.0;
											true ->
												Val = 1.0
										end;
									true ->
										Val = 0.0
								end;
							Pn /= 0 ->
								if
									(RM - R0) < 2 ->
										if 
											VPM < 5 ->
												Val = 0.0;
											VP0 > 7 ->
												Val = 5.0;
											true ->
												Val = 1.0
										end;
									true -> Val = 0.0
								end;
							true ->
								Val = 0.0
						end,
						checkDevCards(IDs,Cards,[{road,Val}|Prop])
				end;
		_	-> checkDevCards(IDs,Cards,Prop)
	end.														

%%@doc moveRobberVal calculates the value of playing a knight, and move the robber, depending on the environment.
%%@spec moveRobberVal(ConditionFromCheckDevCards,AgentIds,BlockedResourceType,ListOfVictoryPoints,MaxVictoryPoint) -> MoveRobberValue
%%@end
moveRobberVal(Case,IDs,Type,[VP0,VP1,VP2,VP3],VPM) ->
	io:fwrite("\tDev_Cards: Calculating MoveRobberVal"),
    case Case of
		1 -> if 
				((VP1 > 7) or (VP2 > 7) or (VP3 > 7)) ->
					2.0;
				((Type == 2) or (Type == 4)) and VPM > 4 ->
					1.5;
				true ->
					1.0
			end;
		2 -> if
				VP0 > 7 ->
					5.0;
				VPM > 4 -> 
					1.0;
				true ->
					0.0
			end;
		3 -> if
				VPM > 4  -> 
					1.5;
				true ->
					1.0
			end
	end.


checkRes([],YearRes) -> YearRes;
checkRes([Res|Ress],[C,O,S,We,Wo]) -> case Res of
	{clay,V} -> checkRes(Ress,[C+V,O,S,We,Wo]);
	{ore,V} -> checkRes(Ress,[C,O+V,S,We,Wo]);
	{sheep,V} -> checkRes(Ress,[C,O,S+V,We,Wo]);
	{wheat,V} -> checkRes(Ress,[C,O,S,We+V,Wo]);
	{wood,V} -> checkRes(Ress,[C,O,S,We,Wo+V])
	end.

updateProbs([],Probs,_) -> 
    Probs;
updateProbs([{Card,Nr}|CPlayed],[{Card,CLeft,_Prob}|Probs],Total) -> 
    newCLeft = CLeft - Nr,
    newProb  = CLeft/Total,
    [{Card,newTotal,newProb}|updateProbs(CPlayed,Probs,Total)];
updateProbs(CPlayed,[P|Probs],Total) -> 
    [P|updateProbs(CPlayed,Probs,Total)].                                
